#pragma once

#include "ICameraImpl.h"
#include <d3d9.h>
#include <d3dx9.h>
#include "ViewFrustrum.h"


class CSkyBox;

class CD3DCameraImpl : public ICameraImpl
{
private:
   IDirect3DDevice9& m_d3Device;

   float m_fov;
   float m_nearZPlane;
   float m_farZPlane;
   D3DVIEWPORT9 m_viewport;

   D3DXVECTOR3 m_rightVec;
   D3DXVECTOR3 m_upVec;
   D3DXVECTOR3 m_lookVec;
   D3DXVECTOR3 m_position;
   
   D3DXMATRIX m_mtxIdentity;
   D3DXMATRIX m_mtxView;
   D3DXMATRIX m_mtx2DProjection;
   D3DXMATRIX m_mtx3DProjection;

   CViewFrustrum m_viewFrustrum;

   CSkyBox* m_skyBox;

   bool m_mtxViewDirty;
   bool m_mtxProjectionDirty;

public:
   CD3DCameraImpl(IDirect3DDevice9& d3Device);
   ~CD3DCameraImpl(void);

   void setViewport(UINT x, UINT y, UINT width, UINT height, float nearZPlane, float farZPlane);
   void setFOV(float angle) {m_fov = angle; m_mtxProjectionDirty = true;}

   const D3DXVECTOR3& getPosition() const {return m_position;}
   void setPosition(const D3DXVECTOR3& vec) {m_position = vec; m_mtxViewDirty = true;}

   const D3DXVECTOR3& getRightVec() const {return m_rightVec;}
   void setRightVec(const D3DXVECTOR3& vec) {m_rightVec = vec; m_mtxViewDirty = true;}

   const D3DXVECTOR3& getUpVec() const {return m_upVec;}
   void setUpVec(const D3DXVECTOR3& vec) {m_upVec= vec; m_mtxViewDirty = true;}

   const D3DXVECTOR3& getLookVec() const {return m_lookVec;}
   void setLookVec(const D3DXVECTOR3& vec) {m_lookVec = vec; m_mtxViewDirty = true;}

   void lookAt(const D3DXVECTOR3& lookAtPt);

   void render(const std::vector<IRenderableObject*>& renderableObjects);

   void setSkyBox(CSkyBox& skyBox);

   void updateProjectionMtx();

private:
   void updateViewMtx();

   void render3DElements(const std::vector<IRenderableObject*>& renderableObjects);
};
